package com.runa.rccprotocol.analysis.En13757.decoder;

import com.runa.protocol.util.ByteUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * Data Information Field
 * 数据信息域
 */
public class DIF {
    private static Dif_Function_Int dif_function_int = new Dif_Function_Int();
    private static Dif_Function_Bcd dif_function_bcd_desc = new Dif_Function_Bcd(false);
    private static Dif_Function_Datef dif_function_datef = new Dif_Function_Datef();

    private byte difByte;

    private Integer dataLength;

    private Dif_Function dif_function;

    private AbsEnDecoder decoder;

    private DIF_Type dif_type;

    private List<DIFE> difeList;

    private byte[] dataByte;

    protected DIF(AbsEnDecoder decoder) {
        this.decoder = decoder;
        initValue();
    }

    private void setDIFE(byte dif) {
        int e = ByteUtil.getByBit((dif), 7) & 0xff;
        boolean haveDife = 0x1 == e;
        if (!haveDife) {
            return;
        }
        if (this.difeList == null) {
            this.difeList = new ArrayList<>();
        }
        byte difeByte = decoder.next();
        difeList.add(new DIFE(difeByte));
        setDIFE(difeByte);
        return;
    }

    protected Object handleData() {
        //移动下标到值的位置
        byte next = decoder.next();
        int startIndex = decoder.getCurrentIndex();
        //移动下标到值结束的位置
        decoder.addCurrentIndex(this.dataLength - 1);

        int surplusLen = decoder.length - (startIndex + this.dataLength);
        //如果剩余字节数不够解析了，则只解析剩余的字节，不能够超过字节数组长度
        if (surplusLen < this.dataLength) {
            this.dataLength = surplusLen + this.dataLength;
        }
        dataByte = new byte[this.dataLength];

        System.arraycopy(decoder.dataByte, startIndex, dataByte, 0, this.dataLength);

        Object res = this.dif_function.handle(decoder.dataByte, startIndex, this.dataLength);
        return res;
    }


    public byte[] getDataByte() {
        return dataByte;
    }

    public void setDataByte(byte[] dataByte) {
        this.dataByte = dataByte;
    }

    private void initValue() {
        this.difByte = decoder.next();
        this.setDIFE(difByte);
        int functionCode = ByteUtil.getByBits(difByte, 4, 2);
        switch (functionCode) {
            case 0x00:
                this.dif_type = DIF_Type.instantaneous;
                break;
            case 0x01:
                this.dif_type = DIF_Type.max;
                break;
            case 0x02:
                this.dif_type = DIF_Type.min;
                break;
            case 0x03:
                this.dif_type = DIF_Type.fault;
                break;
        }

    }

    public enum DIF_Type {
        instantaneous, //瞬时
        max, //最大值
        min, //最小值
        fault //错误值
    }

    public byte getDifByte() {
        return difByte;
    }

    public void setDifByte(byte difByte) {
        this.difByte = difByte;
    }

    public Integer getDataLength() {
        return dataLength;
    }

    public void setDataLength(Integer dataLength) {
        this.dataLength = dataLength;
    }

    public Dif_Function getDif_function(VIF vif) {
        return this.dif_function;
    }

    public void setDif_function(VIF vif) {
        int dataDecodeType = ByteUtil.getByBits(difByte, 0, 4) & 0xff;
        switch (dataDecodeType) {
            case 0x1:
                this.dif_function = dif_function_int;
                this.dataLength = 1;
                break;
            case 0x2:
                this.dif_function = dif_function_int;
                this.dataLength = 2;
                break;
            case 0x3:
                this.dif_function = dif_function_int;
                this.dataLength = 3;
                break;
            case 0x4:
                this.dif_function = dif_function_int;
                this.dataLength = 4;
                break;
            case 0x5:
                this.dif_function = dif_function_int;
                this.dataLength = 4;
                break;
            case 0x6:
                this.dif_function = dif_function_int;
                this.dataLength = 6;
                break;
            case 0x7:
                this.dif_function = dif_function_int;
                this.dataLength = 8;
                break;
            case 0x9:
                this.dif_function = dif_function_bcd_desc;
                this.dataLength = 1;
                break;
            case 0xA:
                this.dif_function = dif_function_bcd_desc;
                this.dataLength = 2;
                break;
            case 0xB:
                this.dif_function = dif_function_bcd_desc;
                this.dataLength = 3;
                break;
            case 0xC:
                this.dif_function = dif_function_bcd_desc;
                this.dataLength = 4;
                break;
            case 0xD:
                this.dif_function = dif_function_bcd_desc;
                this.dataLength = 4;
                break;
            case 0xE:
                this.dif_function = dif_function_bcd_desc;
                this.dataLength = 6;
                break;
            case 0xF:
                this.dif_function = dif_function_bcd_desc;
                this.dataLength = 8;
                break;
        }
        if (vif.getDataType() == VIF.VIF_Type.date_f) {
            this.dif_function = dif_function_datef;
        }
    }

    public DIF_Type getDif_type() {
        return dif_type;
    }

    public void setDif_type(DIF_Type dif_type) {
        this.dif_type = dif_type;
    }

    public List<DIFE> getDifeList() {
        return difeList;
    }

    public void setDifeList(List<DIFE> difeList) {
        this.difeList = difeList;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("{");
        sb.append("\"difByte\":")
                .append(String.format("%02X", difByte));
        sb.append(",\"dataLength\":")
                .append(dataLength);
        sb.append(",\"dif_type\":")
                .append(dif_type);
        sb.append(",\"difeList.size\":")
                .append(difeList == null ? null : difeList.size());
        sb.append('}');
        return sb.toString();
    }

    /*public static void main(String[] args) {
        int t = 0xFF;
        byte[] bits = ByteUtil.getBits((byte) t);
        for (int i = 0; i < bits.length; i++) {
            System.out.print(bits[i]);
        }
        System.out.println();
        int byBits = ByteUtil.getByBits((byte) t, 3, 7);
        byte[] bits2 = ByteUtil.getBits((byte) byBits);
        for (int i = 0; i < bits2.length; i++) {
            System.out.print(bits2[i]);
        }
    }*/

    /**
     * Data Information Field Extensions
     * 数据信息扩展域
     */
    class DIFE {
        private byte dife;

        public DIFE(byte dife) {
            this.dife = dife;
        }
    }
}